package com.xp.flow.component;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * LiteFlow基础组件抽象类
 * 提供通用的节点执行逻辑和配置管理功能
 *
 * @author AI Assistant
 * @since 1.0.0
 */
@Slf4j
public abstract class BaseFlowComponent extends NodeComponent {

    @Autowired
    protected ObjectMapper objectMapper;

    /**
     * 获取流程请求参数
     * 在LiteFlow中，通过this.getRequestData()获取流程执行时传入的初始参数
     *
     * @return 流程请求参数
     */
    protected Object getFlowRequestData() {
        try {
            return this.getRequestData();
        } catch (Exception e) {
            log.error("获取流程请求参数失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取流程请求参数并转换为Map
     *
     * @return 流程请求参数Map
     */
    @SuppressWarnings("unchecked")
    protected Map<String, Object> getFlowRequestDataAsMap() {
        try {
            Object requestData = this.getRequestData();
            if (requestData instanceof Map) {
                return (Map<String, Object>) requestData;
            } else if (requestData != null) {
                // 如果不是Map类型，尝试转换为Map
                return objectMapper.convertValue(requestData, Map.class);
            }
        } catch (Exception e) {
            log.error("获取流程请求参数Map失败: {}", e.getMessage(), e);
        }
        return Map.of();
    }

    /**
     * 获取节点配置
     * 在LiteFlow中，tag主要用于组件实例标识，配置信息应通过其他方式传递
     * 这里保留tag的获取方法，但建议使用getFlowRequestData()获取参数
     *
     * @return 节点tag信息
     */
    protected String getNodeTag() {
        try {
            return this.getTag();
        } catch (Exception e) {
            log.error("获取节点tag失败: {}", e.getMessage(), e);
            return "";
        }
    }

    /**
     * 从tag中解析配置（兼容旧版本）
     * 注意：建议使用getFlowRequestData()获取流程参数
     *
     * @return 节点配置对象
     */
    @Deprecated
    protected Map<String, Object> getNodeConfig() {
        try {
            String configStr = this.getTag();
            if (configStr != null && !configStr.isEmpty()) {
                return objectMapper.readValue(configStr, Map.class);
            }
        } catch (Exception e) {
            log.error("解析节点配置失败: {}", e.getMessage(), e);
        }
        return Map.of();
    }

    /**
     * 获取配置项值
     * 优先从流程请求参数中获取，如果没有则从tag配置中获取
     *
     * @param key 配置项键
     * @param defaultValue 默认值
     * @param <T> 值类型
     * @return 配置项值
     */
    @SuppressWarnings("unchecked")
    protected <T> T getConfigValue(String key, T defaultValue) {
        // 优先从流程请求参数中获取
        Map<String, Object> requestData = getFlowRequestDataAsMap();
        Object value = requestData.get(this.getNodeTag()+"_"+key);

        if (value != null) {
            try {
                return (T) value;
            } catch (ClassCastException e) {
                log.warn("配置项类型转换失败: key={}, value={}, expectedType={}",
                        key, value, defaultValue.getClass().getSimpleName());
            }
        }
        return defaultValue;
    }

    /**
     * 从流程请求参数中获取配置项值
     *
     * @param key 配置项键
     * @param defaultValue 默认值
     * @param <T> 值类型
     * @return 配置项值
     */
    @SuppressWarnings("unchecked")
    protected <T> T getRequestConfigValue(String key, T defaultValue) {
        Map<String, Object> requestData = getFlowRequestDataAsMap();
        Object value = requestData.get(key);
        if (value != null) {
            try {
                return (T) value;
            } catch (ClassCastException e) {
                log.warn("请求参数类型转换失败: key={}, value={}, expectedType={}",
                        key, value, defaultValue.getClass().getSimpleName());
            }
        }
        return defaultValue;
    }

    /**
     * 获取输入数据
     * 在LiteFlow中，优先使用getRequestData()获取流程初始参数
     * 也可以通过getContextBean()获取上下文数据
     *
     * @return 输入数据
     */
    @SuppressWarnings("unchecked")
    protected Map<String, Object> getInputData() {
        try {
            // 优先从流程请求参数获取
            Object requestData = this.getRequestData();
            if (requestData instanceof Map) {
                return (Map<String, Object>) requestData;
            } else if (requestData != null) {
                // 尝试转换为Map
                return objectMapper.convertValue(requestData, Map.class);
            }

            // 如果请求参数为空，尝试从上下文获取
            Object contextBean = this.getContextBean(Object.class);
            if (contextBean instanceof Map) {
                return (Map<String, Object>) contextBean;
            }
        } catch (Exception e) {
            log.error("获取输入数据失败: {}", e.getMessage(), e);
        }
        return Map.of();
    }

    /**
     * 设置输出数据
     * 在LiteFlow中，通过setContextBean()方法将数据存储到上下文中，供后续节点使用
     *
     * @param outputData 输出数据
     */
    protected void setOutputData(Map<String, Object> outputData) {
        try {
            if (outputData != null && !outputData.isEmpty()) {
                // 获取DefaultContext并设置数据
                DefaultContext context = this.getContextBean(DefaultContext.class);
                if (context != null) {
                    for (Map.Entry<String, Object> entry : outputData.entrySet()) {
                        context.setData(entry.getKey(), entry.getValue());
                    }
                    log.info("输出数据已存储到上下文: {}", outputData.keySet());
                } else {
                    log.warn("无法获取DefaultContext，设置输出数据失败");
                }
            }
        } catch (Exception e) {
            log.error("设置输出数据失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 设置输出数据对象
     *
     * @param outputData 输出数据对象
     */
    protected void setOutputData(Object outputData) {
        try {
            if (outputData != null) {
                // 获取DefaultContext并设置数据
                DefaultContext context = this.getContextBean(DefaultContext.class);
                if (context != null && outputData instanceof Map) {
                    Map<?, ?> dataMap = (Map<?, ?>) outputData;
                    for (Map.Entry<?, ?> entry : dataMap.entrySet()) {
                        if (entry.getKey() instanceof String) {
                            context.setData((String) entry.getKey(), entry.getValue());
                        }
                    }
                    log.info("输出数据已设置到上下文: {}", outputData);
                } else if (context != null) {
                    // 如果不是Map类型，设置为默认键值
                    context.setData("outputData", outputData);
                    log.info("输出数据已设置到上下文: {}", outputData);
                } else {
                    log.warn("无法获取DefaultContext，设置输出数据失败");
                }
            }
        } catch (Exception e) {
            log.error("设置输出数据对象失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 设置输出数据到上下文
     * @param key 数据键
     * @param value 数据值
     */
    protected void setOutputData(String key, Object value) {
        try {
            // 获取DefaultContext并设置数据
            DefaultContext context = this.getContextBean(DefaultContext.class);
            if (context != null) {
                context.setData(key, value);
                log.info("输出数据已设置到上下文: key={}, value={}", key, value);
            } else {
                log.warn("无法获取DefaultContext，设置输出数据失败");
            }
        } catch (Exception e) {
            log.error("设置输出数据失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录节点执行日志
     *
     * @param message 日志消息
     * @param args 参数
     */
    protected void logExecution(String message, Object... args) {
        log.info("[{}] {}", this.getClass().getSimpleName(), String.format(message, args));
    }

    /**
     * 记录节点错误日志
     *
     * @param message 错误消息
     * @param throwable 异常
     */
    protected void logError(String message, Throwable throwable) {
        log.error("[{}] {}", this.getClass().getSimpleName(), message, throwable);
    }

    /**
     * 从上下文中获取数据
     * 在LiteFlow中，使用getContextBean()获取上下文对象
     *
     * @param <T> 数据类型
     * @return 上下文数据对象
     */
    @SuppressWarnings("unchecked")
    protected <T> T getContextData() {
        try {
            return (T) this.getContextBean(Object.class);
        } catch (Exception e) {
            log.error("从上下文获取数据失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 从上下文中获取指定类型的数据
     *
     * @param clazz 数据类型
     * @param <T> 数据类型
     * @return 上下文数据对象
     */
    protected <T> T getContextData(Class<T> clazz) {
        try {
            return this.getContextBean(clazz);
        } catch (Exception e) {
            log.error("从上下文获取指定类型数据失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 验证必需的配置项
     * 优先从流程请求参数中验证，如果没有则从tag配置中验证
     *
     * @param requiredKeys 必需的配置项键
     * @throws IllegalArgumentException 如果缺少必需配置项
     */
    protected void validateRequiredConfig(String... requiredKeys) {
        Map<String, Object> requestData = getFlowRequestDataAsMap();
//        Map<String, Object> config = getNodeConfig();
        String tag = getNodeTag();

        for (String key : requiredKeys) {
            boolean hasInRequest = requestData.containsKey(tag+"_"+key) && requestData.get(tag+"_"+key) != null;
//            boolean hasInConfig = config.containsKey(key) && config.get(key) != null;

            if (!hasInRequest ) {
                throw new IllegalArgumentException("缺少必需的配置项: " + tag+"_"+key);
            }
        }
    }

    /**
     * 验证必需的请求参数
     *
     * @param requiredKeys 必需的请求参数键
     * @throws IllegalArgumentException 如果缺少必需参数
     */
    protected void validateRequiredRequestParams(String... requiredKeys) {
        Map<String, Object> requestData = getFlowRequestDataAsMap();
        for (String key : requiredKeys) {
            if (!requestData.containsKey(key) || requestData.get(key) == null) {
                throw new IllegalArgumentException("缺少必需的请求参数: " + key);
            }
        }
    }

    /**
     * 抽象方法：执行节点逻辑
     * 子类必须实现此方法来定义具体的节点行为
     */
    @Override
    public abstract void process();
}
